﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Apm.cs" company="Rolosoft Ltd">
//   © Rolosoft Ltd
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

#region License

// Copyright 2013 Rolosoft Ltd
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#endregion

namespace Rsft.Net.Dns.Extensions
{
    #region Usings

    using System;
    using System.Threading.Tasks;

    #endregion

    /// <summary>
    ///     The APM helpers.
    /// </summary>
    public static class Apm
    {
        #region Public Methods and Operators

        /// <summary>
        /// Task to APM.
        /// </summary>
        /// <param name="task">
        /// The task.
        /// </param>
        /// <param name="callback">
        /// The callback.
        /// </param>
        /// <param name="state">
        /// The state.
        /// </param>
        /// <typeparam name="T">
        /// The type.
        /// </typeparam>
        /// <returns>
        /// The <see cref="System.IAsyncResult"/>.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// "task" is null or not supplied.
        /// </exception>
        public static IAsyncResult AsApm<T>(this Task<T> task, AsyncCallback callback, object state)
        {
            if (task == null)
            {
                throw new ArgumentNullException("task");
            }

            var tcs = new TaskCompletionSource<T>(state);
            task.ContinueWith(
                t =>
                    {
                        if (t.IsFaulted)
                        {
                            if (t.Exception != null)
                            {
                                tcs.TrySetException(t.Exception.InnerExceptions);
                            }
                        }
                        else if (t.IsCanceled)
                        {
                            tcs.TrySetCanceled();
                        }
                        else
                        {
                            tcs.TrySetResult(t.Result);
                        }

                        if (callback != null)
                        {
                            callback(tcs.Task);
                        }
                    }, 
                TaskScheduler.Default);
            return tcs.Task;
        }

        /// <summary>
        /// The as APM.
        /// </summary>
        /// <param name="task">
        /// The task.
        /// </param>
        /// <param name="callback">
        /// The callback.
        /// </param>
        /// <param name="state">
        /// The state.
        /// </param>
        /// <returns>
        /// The <see cref="IAsyncResult"/>.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// "task" is null or not supplied.
        /// </exception>
        public static IAsyncResult AsApm(this Task task, AsyncCallback callback, object state)
        {
            if (task == null)
            {
                throw new ArgumentNullException("task");
            }

            var tcs = new TaskCompletionSource<VoidTypeStruct>(state);
            task.ContinueWith(
                t =>
                    {
                        if (t.IsFaulted)
                        {
                            if (t.Exception != null)
                            {
                                tcs.TrySetException(t.Exception.InnerExceptions);
                            }
                        }
                        else if (t.IsCanceled)
                        {
                            tcs.TrySetCanceled();
                        }
                        else
                        {
                            tcs.TrySetResult(new VoidTypeStruct());
                        }

                        if (callback != null)
                        {
                            callback(tcs.Task);
                        }
                    }, 
                TaskScheduler.Default);
            return tcs.Task;
        }

        #endregion
    }
}